package com.zzyl.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import com.zzyl.base.ResponseResult;
import com.zzyl.constant.CacheConstants;
import com.zzyl.constant.SuperConstant;
import com.zzyl.dto.ResourceDto;
import com.zzyl.entity.Resource;
import com.zzyl.enums.BasicEnum;
import com.zzyl.exception.BaseException;
import com.zzyl.mapper.ResourceMapper;
import com.zzyl.service.ResourceService;
import com.zzyl.utils.EmptyUtil;
import com.zzyl.utils.NoProcessing;
import com.zzyl.utils.StringUtils;
import com.zzyl.vo.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PathVariable;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class ResourceServiceImpl implements ResourceService {

    @Autowired
    private ResourceMapper resourceMapper;

    /**
     * 多条件查询资源列表
     *
     * @param resourceDto
     * @return
     */
    @Override
    @Cacheable(value = CacheConstants.LIST,key = "#resourceDto.hashCode()")
    public List<ResourceVo> findResourceList(ResourceDto resourceDto) {
        List<Resource> resourceList = resourceMapper.selectList(resourceDto);

        return BeanUtil.copyToList(resourceList, ResourceVo.class);
    }

    /**
     * 返回资源树形结构
     *
     * @param resourceDto
     * @return
     */
    @Override
    @Cacheable(value = CacheConstants.TREE)
    public TreeVo resourceTreeVo(ResourceDto resourceDto) {
        ResourceDto dto = ResourceDto.builder()
                .dataState(SuperConstant.DATA_STATE_0)//资源的状态为已启用
                .parentResourceNo(NoProcessing.processString(SuperConstant.ROOT_PARENT_ID))//根路径模糊查询
                .resourceType(SuperConstant.MENU).build();//只要菜单

        //查询所有的资源数据
        List<Resource> resourceList = resourceMapper.selectList(dto);

        //判断resourceList是否为空
        if (EmptyUtil.isNullOrEmpty(resourceList)) {
            throw new RuntimeException("资源信息未定义");
        }

        //组成tree树
        //没有根节点
        Resource rootResource = new Resource();
        rootResource.setResourceNo(SuperConstant.ROOT_PARENT_ID);//智慧养老院的父节点
        rootResource.setResourceName("智慧养老院");

        //返回的树形集合
        List<TreeItemVo> itemVos = new ArrayList<>();

        //使用递归构建树形结构
        recursionTreeItem(itemVos, rootResource, resourceList);

        return TreeVo.builder()
                .items(itemVos)
                .build();
    }


    /**
     * 递归构建资源树
     * <p>
     * 该方法用于将给定的资源列表构建成一个树形结构的列表
     * 它通过递归地查找每个资源的子资源，并将它们构建成子树，最终形成一个完整的资源树
     *
     * @param itemVos      用于存储构建好的树形结构的列表
     * @param rootResource 当前正在处理的根资源
     * @param resourceList 包含所有资源的列表
     */
    private void recursionTreeItem(List<TreeItemVo> itemVos, Resource rootResource, List<Resource> resourceList) {
        //构建每个资源的属性
        TreeItemVo treeItemVo = TreeItemVo.builder().id(rootResource.getResourceNo())
                .label(rootResource.getResourceName())
                .build();

        //获取当前资源下的子资源
        List<Resource> childrenResourceList = resourceList.stream().filter(n -> n.getParentResourceNo().equals(rootResource.getResourceNo()))
                .collect(Collectors.toList());

        //判断子资源是否为空
        if (!EmptyUtil.isNullOrEmpty(childrenResourceList)) {
            //不是空就到集合里面继续遍历封装
            List<TreeItemVo> listChildren = new ArrayList<>();

            //构建子资源
            childrenResourceList.forEach(resource -> {
                //递归调用这个方法
                recursionTreeItem(listChildren, resource, resourceList);
            });

            treeItemVo.setChildren(listChildren);
        }

        itemVos.add(treeItemVo);
    }


    /**
     * 添加资源
     *
     * @param resourceDto
     * @return
     */
    @Override
    @Caching(evict = {
            @CacheEvict(value = CacheConstants.LIST, allEntries = true),//清空里面的缓存
            @CacheEvict(value = CacheConstants.TREE,allEntries = true)//清空缓存
    })
    public void createResource(ResourceDto resourceDto) {
        //业务流程:
        //属性拷贝
        Resource resource = BeanUtil.toBean(resourceDto, Resource.class);

        //1-数据装填要与父资源状态一致
        String parentResourceNo = resourceDto.getParentResourceNo();
        Resource parentResource = resourceMapper.selectByResourceNo(parentResourceNo);
        resource.setDataState(parentResource.getDataState());

        //判断是否为按钮
        boolean isIgnore = true;
        //判断是否是按钮，如果是按钮则不限制层级
        if (StringUtils.isNotEmpty(resourceDto.getResourceType())
                && resourceDto.getResourceType().equals(SuperConstant.BUTTON)) {

            isIgnore = false;
        }
        //2-根据父资源编号创建生成子资源编号
        String resourceNo = createResourceNo(parentResourceNo, isIgnore);

        resource.setResourceNo(resourceNo);

        //5：保存数据
        resourceMapper.insert(resource);
    }


    /**
     * 生成当前资源编号
     *
     * @param parentResourceNo
     * @param isIgnore
     * @return
     */
    private String createResourceNo(String parentResourceNo, boolean isIgnore) {
        //判断是否为按钮,如果菜单大于3级，不允许添加
        if (isIgnore && NoProcessing.processString(parentResourceNo).length() / 3 >= 5) {
            throw new BaseException(BasicEnum.RESOURCE_DEPTH_UPPER_LIMIT);
        }

        //4-父资源是否有子资源
        List<Resource> resourceList = resourceMapper.selectList(ResourceDto.builder().parentResourceNo(parentResourceNo).build());

        if (EmptyUtil.isNullOrEmpty(resourceList)) {
            //4-1-无：根据父资源编号创建新的节点编号
            return NoProcessing.createNo(parentResourceNo, false);
        } else {
            //4-2有：根据子资源编号创建新的节点编号
            //获取最大的子资源编号
            Long maxNo = resourceList.stream().map(resource -> {
                return Long.valueOf(resource.getResourceNo());
            }).max(Comparator.comparing(i -> i)).get();

            return NoProcessing.createNo(String.valueOf(maxNo), true);
        }
    }


    /**
     * 修改资源
     *
     * @param resourceDto
     */
    @Override
    @Caching(evict = {
            @CacheEvict(value = CacheConstants.LIST, allEntries = true),//清空里面的缓存
            @CacheEvict(value = CacheConstants.TREE,allEntries = true)//清空缓存
    })
    public void updateResource(ResourceDto resourceDto) {
        Resource resource = BeanUtil.toBean(resourceDto, Resource.class);
        resourceMapper.updateByPrimaryKeySelective(resource);

    }

    /**
     * 启用禁用资源
     *
     * @param resourceDto
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    @Caching(evict = {
            @CacheEvict(value = CacheConstants.LIST, allEntries = true),//清空里面的缓存
            @CacheEvict(value = CacheConstants.TREE,allEntries = true)//清空缓存
    })
    public void startOrStopResource(ResourceDto resourceDto) {
        //当前菜单实体
        Resource resource = BeanUtil.toBean(resourceDto, Resource.class);

        //查询子级菜单
        String s = NoProcessing.processString(resource.getResourceNo());

        //查找所有的子节点
        resourceDto.setParentResourceNo(s);//父级编号
        resourceDto.setDataState(null);
        List<Resource> resourceList = resourceMapper.selectList(resourceDto);


        //业务流程:
        if (resource.getDataState().equals(SuperConstant.DATA_STATE_1)) {//禁用
            //1-禁用逻辑：
            //禁用当前菜单
            resourceMapper.updateByPrimaryKeySelective(resource);

            //如果下方有子级菜单，子级菜单一起禁用
            updateAllChildrenResource(resourceList, SuperConstant.DATA_STATE_1);

        } else if (resource.getDataState().equals(SuperConstant.DATA_STATE_0)) {//启用
            //2-启用逻辑

            //查询父级菜单是否为禁用状态
            Resource parentResource = resourceMapper.selectByResourceNo(resource.getParentResourceNo());
            if (parentResource != null && parentResource.getDataState().equals(SuperConstant.DATA_STATE_1)) {
                //父级菜单为禁用状态，不允许启用
                throw new BaseException(BasicEnum.PARENT_MENU_DISABLE);
            } else {
                //父级为启用状态，则启用当前菜单
                resourceMapper.updateByPrimaryKeySelective(resource);

                //修改子所有子节点状态
                updateAllChildrenResource(resourceList, SuperConstant.DATA_STATE_0);

            }
        }

    }




    /**
     * 修改子节点
     */
    private void updateAllChildrenResource(List<Resource> resourceList, String dataState) {

        if (!EmptyUtil.isNullOrEmpty(resourceList)) {
            resourceList.stream().forEach(resource -> resource.setDataState(dataState));

            resourceList.forEach(resource -> {
                //修改子节点状态
                resourceMapper.updateByPrimaryKeySelective(resource);
            });
        }

    }

    /**
     * 删除资源
     * @param resourceNo
     */

    /**
     * 删除资源
     *
     * @param resourceNo 资源编号
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    @Caching(evict = {
            @CacheEvict(value = CacheConstants.LIST, allEntries = true),//清空里面的缓存
            @CacheEvict(value = CacheConstants.TREE,allEntries = true)//清空缓存
    })
    public void deleteResource(String resourceNo) {
        // 查询当前资源是否存在
        Resource resource = resourceMapper.selectByResourceNo(resourceNo);
        if (resource == null) {
            throw new BaseException(BasicEnum.RESOURCE_NOT_EXIST);
        }

        // 查询是否有子资源
        List<Resource> childrenResourcesList = resourceMapper.selectList(
                ResourceDto.builder().parentResourceNo(NoProcessing.processString(resourceNo)).build()
        );

        if (!EmptyUtil.isNullOrEmpty(childrenResourcesList)) {
            // 如果存在子资源，级联删除
            throw new RuntimeException("存在子菜单，不允许删除");
        }else {
            // 删除当前资源
            resourceMapper.deleteByResourceNo(resourceNo);
        }
    }

    /**
     * 根据用户id查询对应的资源数据
     * @param userId
     * @return
     */
    @Override
    public List<MenuVo> menus(Long userId) {
        //查询用户对应的所有的菜单数据
        List<MenuVo> menuVoList = resourceMapper.findListByUserId(userId);
        if (CollUtil.isEmpty(menuVoList)) {
            throw new BaseException(BasicEnum.USER_ROLE_AND_MENU_EMPTY);
        }
        //数据进行分组（parentNo:[{},{}]）
        Map<String, List<MenuVo>> parentRNoMap = menuVoList
                .stream()
                .collect(Collectors.groupingBy(MenuVo::getParentResourceNo));
        //遍历所有数据
        menuVoList.forEach(menuVo -> {
            menuVo.setMeta(MenuMetaVo.builder().title(menuVo.getName()).build());
            menuVo.setRedirect("/"+menuVo.getName());
            //根据父编号到map中查找是否包含子菜单，如果包含则设置为当前菜单的子菜单
            List<MenuVo> menuVos = parentRNoMap.get(menuVo.getResourceNo());
            if(!EmptyUtil.isNullOrEmpty(menuVos)){
                menuVos.forEach(m->{
                    m.setMeta(MenuMetaVo.builder().title(menuVo.getName()).build());
                    m.setRedirect(m.getName());
                });
                menuVo.setChildren(menuVos);
            }
        });
        //根据根编号查找所有的子
        return parentRNoMap.get(SuperConstant.ROOT_PARENT_ID);
    }
}
